package Q17_22_Word_Transformer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import CtCILibrary.HashMapList;
public class QuestionC {
public static LinkedList<String> transform(String startWord, String stopWord, String[] words) {
HashMapList<String, String> wildcardToWordList = getWildcardToWordList(words);
BFSData sourceData = new BFSData(startWord);
BFSData destData = new BFSData(stopWord);
while (!sourceData.isFinished() && !destData.isFinished()) {
/* Search out from source. */
String collision = searchLevel(wildcardToWordList, sourceData, destData);
if (collision != null) {
return mergePaths(sourceData, destData, collision);
}
/* Search out from destination. */
collision = searchLevel(wildcardToWordList, destData, sourceData);
if (collision != null) {
return mergePaths(sourceData, destData, collision);
}
}
return null;
}
/* Search one level and return collision, if any. */
public static String searchLevel(HashMapList<String, String> wildcardToWordList, BFSData primary, BFSData secondary) {
/* We only want to search one level at a time. Count how many nodes are currently in the primary's
* level and only do that many nodes. We'll continue to add nodes to the end. */
int count = primary.toVisit.size();
for (int i = 0; i < count; i++) {
/* Pull out first node. */
PathNode pathNode = primary.toVisit.poll();
String word = pathNode.getWord();
/* Check if it's already been visited. */
if (secondary.visited.containsKey(word)) {
return pathNode.getWord();
}
/* Add friends to queue. */
ArrayList<String> words = getValidLinkedWords(word, wildcardToWordList);
for (String w : words) {
if (!primary.visited.containsKey(w)) {
PathNode next = new PathNode(w, pathNode);
primary.visited.put(w, next);
primary.toVisit.add(next);
}
}
}
return null;
}
public static LinkedList<String> mergePaths(BFSData bfs1, BFSData bfs2, String connection) {
PathNode end1 = bfs1.visited.get(connection); // end1 -> source
PathNode end2 = bfs2.visited.get(connection); // end2 -> dest
LinkedList<String> pathOne = end1.collapse(false); // forward: source -> connection
LinkedList<String> pathTwo = end2.collapse(true); // reverse: connection -> dest
pathTwo.removeFirst(); // remove connection
pathOne.addAll(pathTwo); // add second path
return pathOne;
}
public static ArrayList<String> getWildcardRoots(String word) {
ArrayList<String> words = new ArrayList<String>();
for (int i = 0; i < word.length(); i++) {
String w = word.substring(0, i) + "_" + word.substring(i + 1);
words.add(w);
}
return words;
}
public static HashMapList<String, String> getWildcardToWordList(String[] words) {
HashMapList<String, String> wildcardToWords = new HashMapList<String, String>();
for (String word : words) {
ArrayList<String> linked = getWildcardRoots(word);
for (String linkedWord : linked) {
wildcardToWords.put(linkedWord, word);
}
}
return wildcardToWords;
}
public static ArrayList<String> getValidLinkedWords(String word, HashMapList<String, String> wildcardToWords) {
ArrayList<String> wildcards = getWildcardRoots(word);
ArrayList<String> linkedWords = new ArrayList<String>();
for (String wildcard : wildcards) {
ArrayList<String> words = wildcardToWords.get(wildcard);
for (String linkedWord : words) {
if (!linkedWord.equals(word)) {
linkedWords.add(linkedWord);
}
}
}
return linkedWords;
}
public static void main(String[] args) {
String[] words = {"maps", "tan", "tree", "apple", "cans", "help", "aped", "pree", "pret", "apes", "flat", "trap", "fret", "trip", "trie", "frat", "fril"};
LinkedList<String> list = transform("tree", "flat", words);
if (list == null) {
System.out.println("No path.");
} else {
System.out.println(list.toString());
}
}
}